package com.googlecode.afdbaccess.web.common.servletfilter.sessionlesscookieauthentication;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.junit.Assert;
import org.junit.Test;

public class ByteArrayCrypterTest {

    @Test
    public void testEncryptUnencrypt() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidParameterSpecException, NoSuchPaddingException, IOException, InvalidAlgorithmParameterException {
        // Given
        final ByteArrayCrypter byteArrayCrypter = new ByteArrayCrypter("key");
        final byte[] bytesToEncrypt = { 1, 2, 3, 4, 5, 6, 7 };
        
        // When
        final String encryptedString = byteArrayCrypter.encrypt(bytesToEncrypt);
        
        final byte[] unencryptedBytes = byteArrayCrypter.decrypt(encryptedString);
        
        // Then
        Assert.assertArrayEquals(bytesToEncrypt, unencryptedBytes);
    }
    
    @Test(expected = BadPaddingException.class)
    public void testKeyMatters() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidParameterSpecException, NoSuchPaddingException, IOException, InvalidAlgorithmParameterException {
        // Given
        final ByteArrayCrypter byteArrayCrypter1 = new ByteArrayCrypter("key1");
        final ByteArrayCrypter byteArrayCrypter2 = new ByteArrayCrypter("key2");
        final byte[] bytesToEncrypt = { 1, 2, 3, 4, 5, 6, 7 };
        
        // When
        final String encryptedString = byteArrayCrypter1.encrypt(bytesToEncrypt);
        
        byteArrayCrypter2.decrypt(encryptedString);
        
        // Then
        Assert.fail("Should have gotten exception that content could not be decrypted due to differing keys");
    }

    @Test
    public void testNotSameTwice1() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidParameterSpecException, NoSuchPaddingException, IOException {
        // Given
        final ByteArrayCrypter byteArrayCrypter = new ByteArrayCrypter("key");
        final byte[] bytesToEncrypt = { 1, 2, 3, 4, 5, 6, 7 };
        
        // When
        final String encryptedString1 = byteArrayCrypter.encrypt(bytesToEncrypt);
        final String encryptedString2 = byteArrayCrypter.encrypt(bytesToEncrypt);
        final String encryptedString3 = byteArrayCrypter.encrypt(bytesToEncrypt);
        
        // Then
        Assert.assertFalse(encryptedString1.equals(encryptedString2));
        Assert.assertFalse(encryptedString1.equals(encryptedString3));
        Assert.assertFalse(encryptedString2.equals(encryptedString3));
    }

    @Test
    public void testNotSameTwice2() throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidParameterSpecException, NoSuchPaddingException, IOException {
        // Given
        final String key = "key";
        ByteArrayCrypter byteArrayCrypter1 = new ByteArrayCrypter(key);
        ByteArrayCrypter byteArrayCrypter2 = new ByteArrayCrypter(key);
        final byte[] bytesToEncrypt = { 1, 2, 3, 4, 5, 6, 7 };
        
        // When
        final String encryptedString1_1 = byteArrayCrypter1.encrypt(bytesToEncrypt);
        final String encryptedString1_2 = byteArrayCrypter1.encrypt(bytesToEncrypt);
        
        final String encryptedString2_1 = byteArrayCrypter2.encrypt(bytesToEncrypt);
        final String encryptedString2_2 = byteArrayCrypter2.encrypt(bytesToEncrypt);
        
        // Then
        Assert.assertFalse(encryptedString1_1.equals(encryptedString1_2));
        Assert.assertFalse(encryptedString1_1.equals(encryptedString2_1));
        Assert.assertFalse(encryptedString1_1.equals(encryptedString2_1));
        
        Assert.assertFalse(encryptedString1_2.equals(encryptedString2_1));
        Assert.assertFalse(encryptedString1_2.equals(encryptedString2_2));
        
        Assert.assertFalse(encryptedString2_1.equals(encryptedString2_2));
    }
}
